use std::cell::{Cell, RefCell};
use std::ops::Deref;
use crate::byte_data_reader::ByteDataReader;
use crate::cf_constant_info::{CFCONSTANT_INFO_INVALID, CFConstantInfoClass, CFConstantInfoEnum, CFConstantInfoInvalid, create_constant_info};
use crate::cp_attribute_info::{AttributeInfoEnum, create_attribute_info};

/// ClassFile {
///     u4             magic;
///     u2             minor_version;
///     u2             major_version;
///     u2             constant_pool_count;
///     cp_info        constant_pool[constant_pool_count-1];
///     u2             access_flags;
///     u2             this_class;
///     u2             super_class;
///     u2             interfaces_count;
///     u2             interfaces[interfaces_count];
///     u2             fields_count;
///     field_info     fields[fields_count];
///     u2             methods_count;
///     method_info    methods[methods_count];
///     u2             attributes_count;
///     attribute_info attributes[attributes_count];
/// }
pub struct ClassFile {
    // cf_constant_pool_count: u16,
    pub cf_constant_pool: RefCell<Vec<CFConstantInfoEnum>>,
    pub access_flags: u16,
    pub this_class: u16,
    pub super_class: u16,
    // interfaces_count: u16,
    pub interfaces: RefCell<Vec<u16>>,
    // fields_count: u16,
    pub fields: RefCell<Vec<FieldInfo>>,
    pub methods: RefCell<Vec<MethodInfo>>,
    pub attributes: RefCell<Vec<AttributeInfoEnum>>,
}

/// field_info {
///     u2             access_flags;
///     u2             name_index;
///     u2             descriptor_index;
///     u2             attributes_count;
///     attribute_info attributes[attributes_count];
/// }
/// method_info {
///     u2             access_flags;
///     u2             name_index;
///     u2             descriptor_index;
///     u2             attributes_count;
///     attribute_info attributes[attributes_count];
/// }
pub struct FieldInfo {
    pub access_flags: u16,
    pub name_index: u16,
    pub descriptor_index: u16,
    // attributes_count: u16,
    pub attributes: RefCell<Vec<AttributeInfoEnum>>,
}

pub struct MethodInfo {
    pub access_flags: u16,
    pub name_index: u16,
    pub descriptor_index: u16,
    // attributes_count: u16,
    pub attributes: RefCell<Vec<AttributeInfoEnum>>,
}


impl ClassFile {
    pub fn create(reader: &mut ByteDataReader) -> Result<ClassFile, String> {
        let magic = reader.read_u32();
        let minor_version = reader.read_u16();
        let major_version = reader.read_u16();
        println!("magic:{}, minor_version:{}, major_version:{}", magic, minor_version, major_version);
        let cf_constant_pool_count = reader.read_u16();
        let mut cf_constant_pool: RefCell<Vec<CFConstantInfoEnum>> = RefCell::new(Vec::new());

        // cf_constant_pool[0]的元素为一个无效元素
        cf_constant_pool.borrow_mut().push(CFConstantInfoEnum::CFConstantInfoInvalid(CFCONSTANT_INFO_INVALID));
        let mut i = 1;
        while i < cf_constant_pool_count {
            let result = create_constant_info(reader);
            match result {
                Ok(cf_constant_info_enum) => {
                    let mut rw_cf_constant_pool = cf_constant_pool.borrow_mut();
                    rw_cf_constant_pool.push(cf_constant_info_enum);
                    let last = rw_cf_constant_pool.last().unwrap();
                    match last {
                        CFConstantInfoEnum::CFConstantInfoDouble(_) | CFConstantInfoEnum::CFConstantInfoLong(_) => {
                            rw_cf_constant_pool.push(CFConstantInfoEnum::CFConstantInfoInvalid(CFCONSTANT_INFO_INVALID));
                            i = i + 2;
                        }
                        _ => {
                            i = i + 1;
                        }
                    }
                }
                Err(err) => {
                    i = i + 1;
                    println!("err:{}", err);
                }
            };
        }
        let access_flags = reader.read_u16();
        let this_class = reader.read_u16();
        let super_class = reader.read_u16();

        // 解析接口
        let interfaces_count = reader.read_u16();
        let interfaces = RefCell::new(vec![]);
        for _ in 0..interfaces_count {
            interfaces.borrow_mut().push(reader.read_u16());
        }

        // 解析字段
        let fields = RefCell::new(vec![]);
        let fields_count = reader.read_u16();
        for _ in 0..fields_count {
            let access_flags = reader.read_u16();
            let name_index = reader.read_u16();
            let descriptor_index = reader.read_u16();
            let attributes_count = reader.read_u16();
            let attributes: RefCell<Vec<AttributeInfoEnum>> = RefCell::new(Vec::new());
            for _ in 0..attributes_count {
                let attr_result = create_attribute_info(reader, &cf_constant_pool);
                match attr_result {
                    Ok(attr) => {
                        attributes.borrow_mut().push(attr);
                    }
                    Err(err) => {
                        println!("{}", err)
                    }
                }
            }
            fields.borrow_mut().push(FieldInfo {
                access_flags,
                name_index,
                descriptor_index,
                attributes,
            })
        }

        // 解析方法
        let methods_count = reader.read_u16();
        let methods = RefCell::new(vec![]);
        for _ in 0..methods_count {
            let access_flags = reader.read_u16();
            let name_index = reader.read_u16();
            let descriptor_index = reader.read_u16();
            let attributes_count = reader.read_u16();
            let attributes: RefCell<Vec<AttributeInfoEnum>> = RefCell::new(Vec::new());
            for _ in 0..attributes_count {
                let attr_result = create_attribute_info(reader, &cf_constant_pool);
                match attr_result {
                    Ok(attr) => {
                        attributes.borrow_mut().push(attr);
                    }
                    Err(err) => {
                        println!("{}", err)
                    }
                }
            }
            methods.borrow_mut().push(MethodInfo {
                access_flags,
                name_index,
                descriptor_index,
                attributes,
            })
        }

        // 解析属性
        let attributes_count = reader.read_u16();
        let attributes: RefCell<Vec<AttributeInfoEnum>> = RefCell::new(Vec::new());
        for _ in 0..attributes_count {
            let attr_result = create_attribute_info(reader, &mut cf_constant_pool);
            match attr_result {
                Ok(attr) => {
                    attributes.borrow_mut().push(attr);
                }
                Err(err) => {
                    println!("{}", err)
                }
            }
        }

        return Ok(ClassFile {
            cf_constant_pool,
            access_flags,
            this_class,
            super_class,
            interfaces,
            fields,
            methods,
            attributes,
        });
    }

    pub fn get_cfconstant_info_by_index(&self, index: usize) -> Result<CFConstantInfoEnum, String> {
        let ro_cf_constant_pool = self.cf_constant_pool.borrow();

        if ro_cf_constant_pool.len() <= index {
            return Err(format!("数组越界, len:{}, index:{}", ro_cf_constant_pool.len(), index));
        }
        let result = ro_cf_constant_pool.get(index).unwrap();
        return Ok(result.clone());
    }


    pub fn get_cfconstant_info_utf8from_constant_pool(&self, index: usize) -> Result<String, String> {
        let result = self.get_cfconstant_info_by_index(index);
        return match result {
            Err(msg) => {
                return Err(msg);
            }
            Ok(info) => {
                match info {
                    CFConstantInfoEnum::CFConstantInfoUTF8(utf8) => {
                        return Ok(String::from(&utf8.string));
                    }
                    _ => {
                        return Err(String::from("类型不匹配"));
                    }
                }
            }
        };
    }

    pub fn get_cfconstant_info_class_from_constant_pool(&self, index: usize) -> Result<CFConstantInfoClass, String> {
        let ro_cf_constant_pool = self.cf_constant_pool.borrow();

        if ro_cf_constant_pool.len() <= index {
            return Err(format!("数组越界, len:{}, index:{}", ro_cf_constant_pool.len(), index));
        }
        let result = ro_cf_constant_pool.get(index);
        return match result {
            None => {
                return Err(String::from("数据不存在"));
            }
            Some(info) => {
                match info {
                    CFConstantInfoEnum::CFConstantInfoClass(cf_constant_class) => {
                        return Ok(CFConstantInfoClass {
                            cp_index: cf_constant_class.cp_index
                        });
                    }
                    _ => {
                        return Err(String::from("类型不匹配"));
                    }
                }
            }
        };
    }
}
